'use strict'

const process = require('process');
const EventEmitter3 = require('eventemitter3').EventEmitter3;
const util = require('./util');
const logger = require('./logger')('PeerManager');
const PeerConnection = require('./peer-connect').PeerConnection;
const Signaling = require('./signaling').Signaling;

/**
 * PeerManager
 *    事件:
 *        'ready': 连接到Signaling服务成功后触发, 附带参数 'peerId'
 *        'connection': 有新的远端成功连接到本端,附件参数 'peerConnection'
 *        'error': 出现错误时触发,附加参数 'error'
 *        'destroy': 销毁后触发
 */
class PeerManager extends EventEmitter3 {
  constructor(peerId, options) {
    super();
    this.peerId = peerId;
    this._rtcConfig = options.rtcConfig;
    this._channelId = options.channelId;
    this._peerConnections = {};

    this.autoCloseConncetWhenErrorOccur = !!options.autoCloseConncetWhenErrorOccur;
    this.isReady = false;

    // 信令服务器(websocket)
    this._signaling = new Signaling(options.wsConfig);

    this._addSignalingListener();
    process.nextTick(() => {
      this._signaling.connet();
    });
  }

  _handleSignalingMessage(message) {
    const uid = message.uid             // 序列号
      , type = message.type           // 消息类型
      , peerId = message.peerId       // 发送端 peerId
      , payload = message.payload ? message.payload : {};
    let connectionId = null
      , peerConnection = null;

    if (!type || !peerId) {
      logger.warn('recive a message without type or peerId, ignore it.');
      return;
    }
    logger.debug(`recive ${type} message from ${peerId}`);

    switch (type) {
      case 'CONNECT_REQUEST':
        connectionId = payload.connectionId;
        if (!connectionId) {
          logger.warn(`recive a "${type}" message without connectionId from "${peerId}", ignore it.`);
          return;
        }
        const options = {
          connectionId: payload.connectionId,
          rtcConfig: this._rtcConfig,
        };
        peerConnection = new PeerConnection(peerId, this, options);
        this._addPeerConnection(peerId, peerConnection);
        this.emit('connection', peerConnection);
        break;

      case 'CONNECT_OFFER':
      case 'CONNECT_ANSWER':
      case 'CONNECT_CANDIDATE':
        connectionId = payload.connectionId;
        if (!connectionId) {
          logger.warn(`recive a "${type}" message without connectionId from "${peerId}", ignore it.`);
          return;
        }
        peerConnection = this.getPeerConnection(peerId, connectionId);
        if (!peerConnection) {
          logger.warn(`recive a "${type}" message from "${peerId}" connectionId: ${connectionId} that not found, ignore it.`);
          return;
        }
        peerConnection.handleConnectMessage(message);
        break;

      default:
        logger.warn(`recive a unkown type:"${type}" message from "${peerId}", ignore it.`);
        break;
    }
  }

  _handleSignalingWarn(warn) {
    // logger.warn(warn);
    // 忽略警告
  }

  _handleSignalingError(error) {
    // logger.error(error);
    this.emit('error', error);
  }

  _addSignalingListener() {
    // siganling 启动成功(私有/公共频道都订阅成功)
    this._signaling.once('ready', () => {
      this.isReady = true;
      this.emit('ready', this.peerId);
    });

    // 有消息达到
    this._signaling.on('message', message => {
      this._handleSignalingMessage(message);
    });

    // 出现警告
    this._signaling.on('warn', warn => {
      this._handleSignalingWarn(warn);
    });

    // 出现错误
    this._signaling.on('error', error => {
      this._handleSignalingError(error);
    });

    // siganling已成功关闭
    this._signaling.once('close', () => {});
  }

  _addPeerConnection(peerId, peerConnection) {
    if (!this._peerConnections[peerId]) {
      this._peerConnections[peerId] = [];
    }
    this._peerConnections[peerId].push(peerConnection);

    // 自动关闭出问题的链接
    if (this.autoCloseConncetWhenErrorOccur) {
      peerConnection.once('error', () => {
        logger.info(`error occur, auto close ${peerId} connect ${peerConnection.connectionId}.`);
        peerConnection.close();
      });
    }

    // 节点连接关闭后移除
    peerConnection.once('close', () => {
      const peerConnectionsList = this._peerConnections[peerId];
      for (let i = 0; i < peerConnectionsList.length; i ++) {
        const p = peerConnectionsList[i];
        if (p.connectionId == peerConnection.connectionId) {
          peerConnectionsList.splice(i, 1);
          if (peerConnectionsList.length === 0) {
            delete this._peerConnections[peerId];
          }
          break;
        }
      }
    });
  }

  /**
   * 获取所有连接节点
   */
  getAllPeerConnections() {
    return this._peerConnections;
  }

  /**
   * 查找peerConnection
   * @param {*} peerId
   * @param {*} connectionId
   */
  getPeerConnection(peerId, connectionId) {
    const peerConnectionList = this._peerConnections[peerId];
    if (!peerConnectionList) {
      return null;
    }
    for (let i = 0; i < peerConnectionList.length; i ++) {
      if (peerConnectionList[i].connectionId === connectionId) {
        return peerConnectionList[i];
      }
    }
    return null;
  }

  /**
   * 发送消息
   * @param {*} peerId
   * @param {*} type
   * @param {*} payload
   */
  sendSignalMessage(peerId, type, payload) {
    if (!this.isReady) {
      throw new Error('can not send signal message, not ready!');
    }
    logger.debug(`send ${type} message to ${peerId}`);
    return this._signaling.sendMessage(peerId, {
      type: type,
      peerId: this.peerId,
      payload: payload,
    });
  }

  // /**
  //  * emit 错误
  //  * @param {*} error
  //  */
  // emitError(error) {
  //   logger.error(error);
  //   this.emit('error', error);
  // }

  /**
   * 创建连接
   * @param {*} peerId
   * @param {*} options
   */
  connect(peerId, options={}) {
    if (!this.isReady) {
      throw new Error('can not conect, not ready!');
    }
    // if (!this._signaling.isOpened) {
    //   throw new Error('signaling server lost connect, try later.');
    // }
    options = util.extend(options, {
      rtcConfig: this._rtcConfig,
      isOriginator: true
    });
    const peerConnection = new PeerConnection(peerId, this, options);
    this._addPeerConnection(peerId, peerConnection);
    return peerConnection;
  }

  _closePeerConnections() {
    for (let peerId in this._peerConnections) {
      const peerConnectionList = this._peerConnections[peerId];
      for (let i = 0; i < peerConnectionList.length; i ++) {
        peerConnectionList[i].close();
      }
    }
  }

  _closeSignalingServer() {
    this._signaling.removeAllListeners();
    this._signaling.close();
  }

  /**
   * 销毁 peerManager
   */
  destroy() {
    if (!this.isReady) {
      return;
    }
    this.isReady = false;
    this._closeSignalingServer();
    this._closePeerConnections();
    this.emit('destroy');
  }
}

module.exports.PeerManager = PeerManager;
